﻿using Coldairarrow.Business.AOP;
using Coldairarrow.Business.IT;
using Coldairarrow.Business.PB;
using Coldairarrow.Entity.Base;
using Coldairarrow.Entity.Base_Manage;
using Coldairarrow.Entity.DTO;
using Coldairarrow.Entity.IT;
using Coldairarrow.Entity.PB;
using Coldairarrow.Entity.TD;
using Coldairarrow.IBusiness;
using Coldairarrow.IBusiness.DTO;
using Coldairarrow.Util;
using EFCore.Sharding;
using LinqKit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Coldairarrow.Business.TD
{
    public partial class TD_InStorageBusiness : BaseBusiness<TD_InStorage>, ITD_InStorageBusiness, ITransientDependency
    {
        readonly IOperator _operator;
        readonly IOperatorDept _opdept;
        public TD_InStorageBusiness(IDbAccessor db, IServiceProvider svcProvider, IOperator @operator, IOperatorDept @opdept)
            : base(db)
        {
            _ServiceProvider = svcProvider;
            _operator = @operator;
            _opdept = @opdept;
        }
        readonly IServiceProvider _ServiceProvider;
        public async Task<PageResult<TD_InStorage>> GetDataListAsync(TD_InStoragePageInput input)
        {
            Expression<Func<TD_InStorage, Base_EnumItem, TD_Receiving, Base_User, Base_User, TD_InStorageDTO>> select = (a, b, c, d, e) => new TD_InStorageDTO
            {
                TypeName = b.Name,
                ReCode = c.Code,
                ConfirmUserIdName = d.RealName,
                AuditingName = e.RealName
            };
            select = select.BuildExtendSelectExpre();
            var q = from a in GetIQueryable().AsExpandable()
                    join b in Db.GetIQueryable<Base_EnumItem>() on a.InType equals b.Code into ab
                    from b in ab.Where(u => u.EnumCode.Contains("InStorageType")).DefaultIfEmpty()
                    join c in Db.GetIQueryable<TD_Receiving>() on a.RecId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Db.GetIQueryable<Base_User>() on a.CreatorId equals d.Id into ad
                    from d in ad.DefaultIfEmpty()
                    join e in Db.GetIQueryable<Base_User>() on a.AuditUserId equals e.Id into ae
                    from e in ae.DefaultIfEmpty()
                    select @select.Invoke(a, b, c, d, e);
            q = q
                .Include(i => i.Supplier)
                .Include(i => i.CreateUser)
                .Include(i => i.AuditUser)
                .Include(i=>i.ReCode).Where(w => _operator.Property.DeptIds.Contains(w.StorId));

            var where = LinqHelper.True<TD_InStorage>();
            var search = input.Search;

            //如果物料不为空 和 货位 
            if (!search.MaterialName.IsNullOrEmpty() || !search.LocalName.IsNullOrEmpty() || !search.ConfirmUserIdName.IsNullOrEmpty())
            {
                //TD_InStorDetail  子表
                Expression<Func<TD_InStorDetail, PB_Material, PB_Location, Base_User, TD_InStorDetailDTO>> selectsk = (a, b, c, d) => new TD_InStorDetailDTO
                {
                    MaterialIdName = b.Name,
                    LocalIdName = c.Name,
                    ConfirmUserIdName = d.RealName
                };
                selectsk = selectsk.BuildExtendSelectExpre();
                var k = from a in Db.GetIQueryable<TD_InStorDetail>().AsExpandable()
                        join b in Db.GetIQueryable<PB_Material>() on a.MaterialId equals b.Id into ab
                        from b in ab.DefaultIfEmpty()
                        join c in Db.GetIQueryable<PB_Location>() on a.LocalId equals c.Id into ac
                        from c in ac.DefaultIfEmpty()
                        join d in Db.GetIQueryable<Base_User>() on a.CreatorId equals d.Id into ad
                        from d in ad.DefaultIfEmpty()

                        select @selectsk.Invoke(a, b, c, d);
                if (!search.MaterialName.IsNullOrEmpty())
                    k = k.Where(x => x.MaterialIdName.Contains(search.MaterialName));
                if (!search.LocalName.IsNullOrEmpty())
                    k = k.Where(x => x.LocalIdName.Contains(search.LocalName));
                if (!search.ConfirmUserIdName.IsNullOrEmpty())
                    k = k.Where(x => x.ConfirmUserIdName.Contains(search.ConfirmUserIdName));

                var res = await k.ToListAsync();
                var list = res.GroupBy(x => new { x.InStorId }).Select(x => new { InStorId = x.Key.InStorId });
                List<String> names = new List<string>();
                foreach (var item in list)
                {
                    names.Add(item.InStorId);
                }
                q = q.Where(x => names.Contains(x.Id));
            }

            //此处入库单号和盘点单号查询存在问题
            if (!search.Code.IsNullOrEmpty())
                where = where.And(w => w.Code.Contains(search.Code) || w.RefCode.Contains(search.Code));
            if (!search.InType.IsNullOrEmpty())
                where = where.And(w => w.InType == search.InType);
            if (!search.Rukuid.IsNullOrEmpty())
                where = where.And(w => w.Id .Contains(search.Rukuid));
            if (search.InStorTimeStart.HasValue)
                where = where.And(w => w.InStorTime >= search.InStorTimeStart.Value);
            if (search.InStorTimeEnd.HasValue)
                where = where.And(w => w.InStorTime <= search.InStorTimeEnd.Value);
            if (search.Status.HasValue)
                where = where.And(w => w.Status == search.Status.Value);


            return await q.Where(where).GetPageResultAsync(input);
        }

        public async Task<TD_InStorage> GetTheDataAsync(string id)
        {
            return await this.GetIQueryable()
                .Include(i => i.InStorDetails)
                    .ThenInclude(t => t.Material)
                .Include(i => i.InStorDetails)
                    .ThenInclude(t=>t.Location)
                .Include(i => i.InStorDetails)
                    .ThenInclude(t => t.Location.PB_StorArea)
                      .Include(i => i.InStorDetails)
                    .ThenInclude(t => t.Location.PB_Rack)
                .Include(i => i.InStorDetails)
                    .ThenInclude(t => t.CreateUser)
                .Include(i=>i.InStorRecords)
                    .ThenInclude(t => t.Material)
                .SingleOrDefaultAsync(w => w.Id == id);
        }

        //[LockInstor]
        [DataAddLog(UserLogType.入库管理, "Code", "入库单")]
        [Transactional]
        public async Task AddDataAsync(TD_InStorage data)
        {
            if (data.Code.IsNullOrEmpty())
            {
                data.Code = DateTime.Now.ToString("yyyyMMddHHmmss");
            }
            var detpdata = await _opdept.GetOperatorDept();

            TD_InStorage tD_InStorage = new TD_InStorage();
            tD_InStorage.Id = data.Id;
            tD_InStorage.RecId = data.RecId;
            tD_InStorage.Code = data.Code;
            tD_InStorage.InStorTime = data.InStorTime;
            tD_InStorage.InType = data.InType;
            tD_InStorage.RefCode = data.RefCode.IsNullOrEmpty() ? "" : data.RefCode;
            tD_InStorage.Status = 0;
            tD_InStorage.Remarks = data.Remarks;
            tD_InStorage.StorId = data.StorId;
            tD_InStorage.CreatorId = _operator.UserId;
            tD_InStorage.TotalNum = data.InStorDetails.Sum(s => s.Num);
            tD_InStorage.TotalAmt = data.InStorDetails.Sum(s => s.TotalAmt);
            tD_InStorage.SupId = data.SupId;
            tD_InStorage.CreateTime = data.CreateTime;
            tD_InStorage.Deleted = false;
            tD_InStorage.DepId = detpdata.DetpId;
            tD_InStorage.QrCode = h_Warehousing + "," + data.Id;
            await Db.InsertAsync<TD_InStorage>(tD_InStorage);
            List<TD_InStorDetail> tD_InStorDetaillist = new List<TD_InStorDetail>();
            foreach (var item in data.InStorDetails)
            {
                TD_InStorDetail tD_InStorDetail = new TD_InStorDetail();
                tD_InStorDetail.Id = item.Id;
                tD_InStorDetail.InStorId = item.InStorId;
                tD_InStorDetail.RecordId = item.RecordId;
                tD_InStorDetail.StorId = item.StorId;
                tD_InStorDetail.LocalId = item.LocalId;
                tD_InStorDetail.AreaId = item.AreaId;
                tD_InStorDetail.RackId = item.RackId;
                tD_InStorDetail.BarCode = h_Material + "," + item.MaterialId;
                tD_InStorDetail.MaterialId = item.MaterialId;
                tD_InStorDetail.BatchNo = item.BatchNo;
                tD_InStorDetail.Price = item.Price;
                tD_InStorDetail.TotalAmt = item.TotalAmt;
                tD_InStorDetail.Num = item.Num;
                tD_InStorDetail.CreateTime = item.CreateTime;
                tD_InStorDetail.CreatorId = _operator.UserId;
                tD_InStorDetail.Deleted = false;
                tD_InStorDetaillist.Add(tD_InStorDetail);
            }
            await Db.InsertAsync<TD_InStorDetail>(tD_InStorDetaillist);
            List<TD_InStorRecord> tD_InStorRecordlist = new List<TD_InStorRecord>();
            var list = data.InStorDetails.GroupBy(s => new { s.MaterialId, s.Price }).Select(x => new { MaterialId = x.Key.MaterialId, Price = x.Key.Price, Num = x.Sum(i => i.Num), TotalAmt = x.Sum(i => i.TotalAmt) });
            foreach (var item in list)
            {
                TD_InStorRecord tD_InStorRecord = new TD_InStorRecord();
                tD_InStorRecord.Id = IdHelper.GetId();
                tD_InStorRecord.InStorId = data.Id;
                tD_InStorRecord.StorId = data.StorId;
                tD_InStorRecord.MaterialId = item.MaterialId;
                //tD_InStorRecord.BatchNo = item.BatchNo;
                tD_InStorRecord.Price = item.Price;
                tD_InStorRecord.TotalAmt = item.TotalAmt;
                tD_InStorRecord.Num = item.Num;
                tD_InStorRecord.CreateTime = DateTime.Now;
                tD_InStorRecord.CreatorId = _operator.UserId;
                tD_InStorRecord.Deleted = false;
                tD_InStorRecordlist.Add(tD_InStorRecord);
            }
            await Db.InsertAsync<TD_InStorRecord>(tD_InStorRecordlist);
            //无码入库
            //if (data.InType == "WithoutQRCode")
            //{
            //    List<IT_LocalDetail> iT_LocalDetails = new List<IT_LocalDetail>();
            //    foreach (var item in tD_InStorDetaillist)
            //    {
            //        IT_LocalDetail iT_LocalDetail = new IT_LocalDetail()
            //        {
            //            Id = IdHelper.GetId(),
            //            StorId = item.StorId,
            //            LocalId = item.LocalId,
            //            MaterialId = item.MaterialId,
            //            InTime = DateTime.Now,
            //            CreateTime = DateTime.Now,
            //            CreatorId = _operator.UserId,
            //            Price = item.Price,
            //            Deleted = false,
            //            Num = item.Num,
            //            PackId = "",
            //            JobId = "",
            //            OldOrNew = 0
            //        };
            //        iT_LocalDetails.Add(iT_LocalDetail);
            //    }
            //    await Db.InsertAsync<IT_LocalDetail>(iT_LocalDetails);
            //    List<string> MaterialIds = iT_LocalDetails.Select(x => x.MaterialId).ToList();
            //    List<string> LocalIds= iT_LocalDetails.Select(x => x.LocalId).ToList();
            //    List<PB_Location> pB_Locations = await Db.GetIQueryable<PB_Location>().Where(x => x.StorId == data.StorId && LocalIds.Contains(x.Id)).ToListAsync();

            //    List<IT_LocalMaterial> iT_LocalMaterials = await Db.GetIQueryable<IT_LocalMaterial>().Where(x => x.StorId == data.StorId && MaterialIds.Contains(x.MaterialId) && LocalIds.Contains(x.LocalId)).ToListAsync();

            //    List<IT_LocalMaterial> LocalMaterials = new List<IT_LocalMaterial>();
            //    foreach (var item in iT_LocalDetails)
            //    {
            //        var itemdata = iT_LocalMaterials.Where(x => x.MaterialId == item.MaterialId && x.StorId == item.StorId && x.LocalId == item.LocalId).FirstOrDefault();
            //        if (itemdata.IsNullOrEmpty())
            //        {
            //            IT_LocalMaterial iT_LocalMaterial = new IT_LocalMaterial()
            //            {
            //                Id = IdHelper.GetId(),
            //                MaterialId = item.MaterialId,
            //                StorId = item.StorId,
            //                LocalId = item.LocalId,
            //                AreaId = pB_Locations.Where(x => x.Id == item.LocalId).FirstOrDefault().AreaId,
            //                RackId = pB_Locations.Where(x => x.Id == item.LocalId).FirstOrDefault().RackId,
            //                Nums_N = 0,
            //                Nums_O = Convert.ToDouble(item.Num),
            //                Nums_R = 0,
            //                CreatorId = _operator.UserId,
            //                CreateTime = DateTime.Now,
            //                Deleted = false,
            //                ScanNum = Convert.ToDouble(item.Num),
            //                CheckNum = 0
            //            };
            //            LocalMaterials.Add(iT_LocalMaterial);
            //        }
            //        else
            //        {
            //            itemdata.Nums_O += Convert.ToDouble(item.Num);
            //            itemdata.ScanNum += Convert.ToDouble(item.Num);
            //        }
            //    }
            //    await Db.InsertAsync<IT_LocalMaterial>(LocalMaterials);
            //    if (iT_LocalMaterials.Count > 0)
            //    {
            //        await Db.UpdateAsync<IT_LocalMaterial>(iT_LocalMaterials);
            //    }

            //}

            //增加台账记录。牟俊明。2022.7.8
            //var bookSvc = _ServiceProvider.GetRequiredService<IIT_RecordBookBusiness>();
            //await bookSvc.AddByTypeAsync(data.Id, "In");
        }

        //[LockInstor]
        [DataEditLog(UserLogType.入库管理, "Code", "入库单")]
        [Transactional]
        public async Task UpdateDataAsync(TD_InStorage data)
        {
            await ExecuteSqlAsync("delete from TD_InStorDetail  where InStorId='" + data.Id + "'");

            List<TD_InStorDetail> tD_InStorDetaillist = new List<TD_InStorDetail>();
            foreach (var item in data.InStorDetails)
            {
                TD_InStorDetail tD_InStorDetail = new TD_InStorDetail();
                tD_InStorDetail.Id = item.Id;
                tD_InStorDetail.InStorId = item.InStorId;
                tD_InStorDetail.RecordId = item.RecordId;
                tD_InStorDetail.StorId = item.StorId;
                tD_InStorDetail.LocalId = item.LocalId;
                tD_InStorDetail.AreaId = item.AreaId;
                tD_InStorDetail.RackId = item.RackId;
                tD_InStorDetail.BarCode = item.BarCode;
                tD_InStorDetail.MaterialId = item.MaterialId;
                tD_InStorDetail.BatchNo = item.BatchNo;
                tD_InStorDetail.Price = item.Price;
                tD_InStorDetail.TotalAmt = item.TotalAmt;
                tD_InStorDetail.Num = item.Num;
                tD_InStorDetail.CreateTime = item.CreateTime;
                tD_InStorDetail.CreatorId = _operator.UserId;
                tD_InStorDetail.Deleted = false;
                tD_InStorDetaillist.Add(tD_InStorDetail);
            }
            await Db.InsertAsync<TD_InStorDetail>(tD_InStorDetaillist);


             await ExecuteSqlAsync("delete from TD_InStorRecord  where InStorId='" + data.Id + "'");
            List<TD_InStorRecord> tD_InStorRecordlist = new List<TD_InStorRecord>();
            var list = data.InStorDetails.GroupBy(s => new { s.MaterialId, s.Price }).Select(x => new { MaterialId = x.Key.MaterialId, Price = x.Key.Price, Num = x.Sum(i => i.Num), TotalAmt = x.Sum(i => i.TotalAmt) });
            foreach (var item in list)
            {
                TD_InStorRecord tD_InStorRecord = new TD_InStorRecord();
                tD_InStorRecord.Id = IdHelper.GetId();
                tD_InStorRecord.InStorId = data.Id;
                tD_InStorRecord.StorId = data.StorId;
                tD_InStorRecord.MaterialId = item.MaterialId;
                //tD_InStorRecord.BatchNo = item.BatchNo;
                tD_InStorRecord.Price = item.Price;
                tD_InStorRecord.TotalAmt = item.TotalAmt;
                tD_InStorRecord.Num = item.Num;
                tD_InStorRecord.CreateTime = DateTime.Now;
                tD_InStorRecord.CreatorId = _operator.UserId;
                tD_InStorRecord.Deleted = false;
                tD_InStorRecordlist.Add(tD_InStorRecord);
            }
            await Db.InsertAsync<TD_InStorRecord>(tD_InStorRecordlist);


            TD_InStorage tD_InStorage = await Db.GetIQueryable<TD_InStorage>().Where(s => s.Id == data.Id).FirstOrDefaultAsync();
            tD_InStorage.RecId = data.RecId;
            tD_InStorage.Code = data.Code;
            tD_InStorage.InStorTime = data.InStorTime;
            tD_InStorage.InType = data.InType;
            tD_InStorage.RefCode = data.RefCode;
            tD_InStorage.Status = 0;
            tD_InStorage.Remarks = data.Remarks;
            tD_InStorage.TotalNum = data.InStorDetails.Sum(s => s.Num);
            tD_InStorage.TotalAmt = data.InStorDetails.Sum(s => s.TotalAmt);
            tD_InStorage.SupId = data.SupId;
            List<string> props = GetFieldList(tD_InStorage);
            if (props.IsNullOrEmpty())
            {
                await UpdateAsync(tD_InStorage);
            }
            else
            {
                await UpdateAsync(tD_InStorage, props);
            }
        }

        [DataDeleteLog(UserLogType.入库管理, "Code", "入库单")]
        public async Task DeleteDataAsync(List<string> ids)
        {
            await DeleteAsync(ids);
        }
        [DataEditLog(UserLogType.入库管理, "Id", "入库单审批")]
        [Transactional]
        public async Task Approve(AuditDTO audit)
        {
            var now = DateTime.Now;
            var data = await this.GetTheDataAsync(audit.Id);
            var detail = data.InStorDetails;
            var dicMUnit = detail.Select(s => new { s.MaterialId, s.Material.UnitGroupId }).GroupBy(g => new { g.MaterialId, g.UnitGroupId }).ToDictionary(k => k.Key.MaterialId, v => v.Key.UnitGroupId);

            // 增加库存明细
            {
                var ldGrout = detail
                    .GroupBy(g => new { g.StorId, g.LocalId,  g.MaterialId, g.BatchNo, g.BarCode, g.Price })
                    .Select(s => new { s.Key.StorId, s.Key.LocalId, s.Key.MaterialId, s.Key.BatchNo, s.Key.BarCode, s.Key.Price, TotalAmt = s.Sum(o => o.TotalAmt), Num = s.Sum(o => o.Num) })
                    .ToList();
                var listLd = new List<IT_LocalDetail>();
                foreach (var item in ldGrout)
                {
                    var ld = new IT_LocalDetail();
                    ld.Id = IdHelper.GetId();
                    ld.StorId = audit.StorId;
                    ld.InStorId = audit.Id;
                    ld.LocalId = item.LocalId;
                    ld.MaterialId = item.MaterialId;
                    ld.MeasureId = dicMUnit[item.MaterialId];
                    ld.BatchNo = item.BatchNo;
                    ld.BarCode = item.BarCode;
                    ld.InTime = audit.AuditTime;
                    ld.Amount = item.TotalAmt;
                    ld.CreateTime = now;
                    ld.CreatorId = audit.AuditUserId;
                    ld.Price = item.Price;
                    ld.Num = item.Num;
                    ld.Deleted = false;
                    listLd.Add(ld);
                }
                if (listLd.Count > 0)
                {
                    var localdetailSvc = _ServiceProvider.GetRequiredService<IIT_LocalDetailBusiness>();
                    await localdetailSvc.AddDataAsync(listLd);
                }
            }

            // 增加库存
            {
                var lmGrout = detail
                    .GroupBy(g => new { g.StorId, g.LocalId,  g.MaterialId, g.BatchNo, g.BarCode })
                    .Select(s => new { s.Key.StorId, s.Key.LocalId, s.Key.MaterialId, s.Key.BatchNo, s.Key.BarCode, Num = s.Sum(o => o.Num) })
                    .ToList();
                //查询当前库存记录
                var localIds = lmGrout.Select(s => s.LocalId).ToList();
                var materIds = lmGrout.Select(s => s.MaterialId).ToList();
                var batchNos = lmGrout.Select(s => s.BatchNo).ToList();
                var barCodes = lmGrout.Select(s => s.BarCode).ToList();

                var lmQuery = Db.GetIQueryable<IT_LocalMaterial>();
                lmQuery = lmQuery.Where(w => w.StorId == audit.StorId);
                if (localIds.Count > 0)
                    lmQuery = lmQuery.Where(w => localIds.Contains(w.LocalId));
                if (materIds.Count > 0)
                    lmQuery = lmQuery.Where(w => materIds.Contains(w.MaterialId));
                var lmDbData = await lmQuery.ToListAsync();

                //处理库存
                var localMaterialSvc = _ServiceProvider.GetRequiredService<IIT_LocalMaterialBusiness>();
                var listLmAdd = new List<IT_LocalMaterial>();
                var listLmUpdate = new List<IT_LocalMaterial>();
                foreach (var item in lmGrout)
                {
                    //如果存再当前相同的物料，就在库存上直接相加
                    var lmItem = lmDbData.Where(w => w.StorId == item.StorId && w.LocalId == item.LocalId && w.MaterialId == item.MaterialId ).SingleOrDefault();
                    if (lmItem != null)
                    {
                        lmItem.Nums_N += item.Num;
                        listLmUpdate.Add(lmItem);
                    }
                    else
                    {
                        //如果当前库存不存再相同的物料，就增加此物料的记录
                        var lm = new IT_LocalMaterial();
                        lm.Id = IdHelper.GetId();
                        lm.StorId = item.StorId;
                        lm.LocalId = item.LocalId;
                        lm.MaterialId = item.MaterialId;
                        lm.Nums_N = item.Num;
                        listLmAdd.Add(lm);
                    }
                }
                if (listLmAdd.Count > 0)
                {
                    await localMaterialSvc.AddDataAsync(listLmAdd);
                }
                if (listLmUpdate.Count > 0)
                {
                    await localMaterialSvc.UpdateDataAsync(listLmUpdate);
                }
            }

            // 处理台帐
            {
                var lmGrout = detail
                    .GroupBy(g => new { g.StorId, g.LocalId, g.MaterialId, g.BatchNo, g.BarCode })
                    .Select(s => new { s.Key.StorId, s.Key.LocalId, s.Key.MaterialId, s.Key.BatchNo, s.Key.BarCode, Num = s.Sum(o => o.Num) })
                    .ToList();

                var listRB = new List<IT_RecordBook>();
                foreach (var item in lmGrout)
                {
                    var rb = new IT_RecordBook();
                    rb.Id = IdHelper.GetId();
                    rb.RefCode = data.Code;
                    rb.Type = "In";
                    rb.ToStorId = item.StorId;
                    rb.ToLocalId = item.LocalId;
                    rb.MaterialId = item.MaterialId;
                    rb.MeasureId = dicMUnit[item.MaterialId];
                    rb.BatchNo = item.BatchNo;
                    rb.BarCode = item.BarCode;
                    rb.Num = item.Num;
                    rb.CreateTime = now;
                    rb.CreatorId = audit.AuditUserId;
                    rb.Deleted = false;
                    listRB.Add(rb);
                }
                if (listRB.Count > 0)
                {
                    var bookSvc = _ServiceProvider.GetRequiredService<IIT_RecordBookBusiness>();
                    await bookSvc.AddDataAsync(listRB);
                }
            }

            // 处理托盘位置数据
            {
                var dicTray = new Dictionary<string, string>();
                //foreach (var item in detail)
                //{
                //    if (item.TrayId != null && !dicTray.ContainsKey(item.TrayId))
                //        dicTray.Add(item.TrayId, item.LocalId);
                //}
                var trayIds = dicTray.Keys.ToList();
                if (trayIds.Count > 0)
                {
                    var listTray = await Db.GetIQueryable<PB_Tray>().Where(w => trayIds.Contains(w.Id)).ToListAsync();
                    foreach (var tray in listTray)
                    {
                        tray.LocalId = dicTray[tray.Id];
                    }
                    var traySvc = _ServiceProvider.GetRequiredService<IPB_TrayBusiness>();
                    await traySvc.UpdateDataAsync(listTray);
                }
            }

            // 解锁货位 在自动入库的时候，货位可能被入库锁锁定了
            {
                var localIds = detail.Select(s => s.LocalId).ToList();
                var listLocal = await Db.GetIQueryable<PB_Location>().Where(w => localIds.Contains(w.Id) && w.LockType == 1).ToListAsync();
                //await Db.Update_SqlAsync<PB_Location>(w => localIds.Contains(w.Id) && w.LockType == 1, ("LockType", UpdateType.Equal, 0));
                foreach (var item in listLocal)
                {
                    item.LockType = 0;
                }
                var localSvc = _ServiceProvider.GetRequiredService<IPB_LocationBusiness>();
                await localSvc.UpdateDataAsync(listLocal);
            }

            // 修改主数据状态
            {
                data.Status = 1;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }

            // 更新收货单数据
            if (!data.RecId.IsNullOrEmpty())
            {
                var recSvc = _ServiceProvider.GetRequiredService<ITD_ReceivingBusiness>();
                await recSvc.UpdateByInStorage(data.RecId);
            }
        }

        [DataEditLog(UserLogType.入库管理, "Id", "入库单审批")]
        [Transactional]
        public async Task InApprove(AuditDTO audit)
        {
            var data = await this.GetTheDataAsync(audit.Id);
            // 修改主数据状态
            {
                data.Status = 1;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }
            Base_User bdata = await Db.GetIQueryable<Base_User>().Where(x => x.Id == _operator.UserId).FirstOrDefaultAsync();
            foreach (var item in data.InStorDetails)
            {
                var materdata = await Db.GetIQueryable<IT_LocalMaterial>().Where(x => x.MaterialId == item.MaterialId && x.StorId == item.StorId && x.LocalId == item.LocalId).FirstOrDefaultAsync();
                if (materdata == null)
                {
                    //不存在新增
                    IT_LocalMaterial itdata = new IT_LocalMaterial();
                    itdata.Id = IdHelper.GetId();
                    itdata.MaterialId = item.MaterialId;
                    itdata.StorId = item.StorId;
                    itdata.LocalId = item.LocalId;
                    itdata.Nums_N = item.Num;
                    itdata.CreatorId = _operator.UserId;
                    itdata.CreateTime = DateTime.Now;
                    itdata.Deleted = false;
                    itdata.ScanNum = item.Num;
                    itdata.CheckNum = 0;
                    await Db.InsertAsync<IT_LocalMaterial>(itdata);
                }
                else
                {
                    //存在修改
                    string sqlMain = @"update IT_LocalMaterial set Nums_N=IFNULL(Nums_N,0)+" + item.Num + ",ScanNum=IFNULL(ScanNum,0)+" + item.Num + " where StorId='" + item.StorId + "' and LocalId='" + item.LocalId + "' and MaterialId='" + item.MaterialId + "';update PB_Material set CheckNum=IFNULL(CheckNum,0)+" + item.Num + ", ScanNum=IFNULL(ScanNum,0)+" + item.Num + " where Id='" + item.MaterialId + "'";
                    await ExecuteSqlAsync(sqlMain);
                }
                //库存明细表
                IT_LocalDetail detdata = new IT_LocalDetail();
                detdata.Id = IdHelper.GetId();
                detdata.StorId = item.StorId;
                detdata.LocalId = item.LocalId;
                detdata.MaterialId = item.MaterialId;
                // detdata.MeasureId = Materialdata.storageId;
                detdata.InTime = DateTime.Now;
                detdata.CreateTime = DateTime.Now;
                detdata.CreatorId = _operator.UserId;
                detdata.Deleted = false;
                detdata.Num = item.Num;
                detdata.BarCode = h_Material + "," + item.MaterialId;
                detdata.PackId = "";
                detdata.OldOrNew = 1;
                detdata.JobId = "";
                await Db.InsertAsync<IT_LocalDetail>(detdata);

                //插入库存明细表
                PB_StockLog lodata = new PB_StockLog();
                lodata.Id = IdHelper.GetId();
                //  lodata.PackId = packId;
                lodata.StorId = item.StorId;
                lodata.LocationId = item.LocalId;
                lodata.StockNumber = item.Num;
                lodata.CreatorId = _operator.UserId;
                lodata.CreatorName = bdata.RealName;
                lodata.OperatorId = _operator.UserId;
                lodata.OrderID = item.InStorId;
                lodata.CreateTime = DateTime.Now;
                lodata.Type = 2;
                lodata.State = 0;
                lodata.OldOrNew = 1;
                await Db.InsertAsync<PB_StockLog>(lodata);
            }

            //为收货\回货\外包\退货\其它\无码 入库审核通过新增库存台账记录。 牟俊明。2022.06.15
            //var bookSvc = _ServiceProvider.GetRequiredService<IIT_RecordBookBusiness>();
            //await bookSvc.AddByTypeAsync(audit.Id, "In");
        }
        [DataEditLog(UserLogType.入库管理, "Id", "入库单审批")]
        [Transactional]
        public async Task InReject(AuditDTO audit)
        {
            var data = await this.GetTheDataAsync(audit.Id);
            // 修改主数据状态
            {
                data.Status = 2;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }
        }

        [DataEditLog(UserLogType.入库管理, "Id", "入库单驳回")]
        [Transactional]
        public async Task Reject(AuditDTO audit)
        {
            var data = await this.GetTheDataAsync(audit.Id);
            // 修改主数据状态
            {
                data.Status = 2;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }

            // 解锁货位 在自动入库的时候，货位可能被入库锁锁定了
            {
                var localIds = data.InStorDetails.Select(s => s.LocalId).ToList();
                var listLocal = await Db.GetIQueryable<PB_Location>().Where(w => localIds.Contains(w.Id) && w.LockType == 1).ToListAsync();
                foreach (var item in listLocal)
                {
                    item.LockType = 0;
                }
                var localSvc = _ServiceProvider.GetRequiredService<IPB_LocationBusiness>();
                await localSvc.UpdateDataAsync(listLocal);
            }

            // 更新收货单数据
            if (!data.RecId.IsNullOrEmpty())
            {
                var recSvc = _ServiceProvider.GetRequiredService<ITD_ReceivingBusiness>();
                await recSvc.UpdateByInStorage(data.RecId);
            }
        }

        public async Task InBlankTray(List<KeyValuePair<string, string>> listTray)
        {
            var listTrayIds = listTray.Select(s => s.Key).ToList();
            var trays = await Db.GetIQueryable<PB_Tray>().Where(w => listTrayIds.Contains(w.Id)).ToListAsync();
            var dicLocal = listTray.ToDictionary(k => k.Key, v => v.Value);
            foreach (var tray in trays)
            {
                if (dicLocal.ContainsKey(tray.Id))
                    tray.LocalId = dicLocal[tray.Id];
            }
            var traySvc = _ServiceProvider.GetRequiredService<IPB_TrayBusiness>();
            await traySvc.UpdateDataAsync(trays);
        }

        [Transactional(System.Data.IsolationLevel.Serializable)]
        public async Task<string> ReqLocation((string StorId, string MaterialId, string TaryId) data)
        {
            //托盘类型
            var tray = await Db.GetIQueryable<PB_Tray>().SingleOrDefaultAsync(w => w.Id == data.TaryId);

            //找到可存此物料的货区
            var listAreaId = from sa in Db.GetIQueryable<PB_StorArea>()
                             join am in Db.GetIQueryable<PB_AreaMaterial>() on sa.Id equals am.AreaId
                             where sa.StorId == data.StorId && am.MaterialId == data.MaterialId
                             select sa.Id;

            //有库存的货位
            var lmLocal = from lm in Db.GetIQueryable<IT_LocalMaterial>()
                          join l in Db.GetIQueryable<PB_Location>() on lm.LocalId equals l.Id
                          where l.StorId == data.StorId && lm.StorId == data.StorId
                          select l.Id;

            // 有托盘的货位
            var trayLocal = from t in Db.GetIQueryable<PB_Tray>()
                            join l in Db.GetIQueryable<PB_Location>() on t.LocalId equals l.Id
                            where l.StorId == data.StorId
                            select t.LocalId;

            //过滤货位
            var LocalQuery = from lt in Db.GetIQueryable<PB_LocalTray>()
                             join l in Db.GetIQueryable<PB_Location>() on lt.LocalId equals l.Id
                             join tt in Db.GetIQueryable<PB_TrayType>() on lt.TrayTypeId equals tt.Id
                             where l.StorId == data.StorId && tt.Id == tray.TrayTypeId
                             && l.IsForbid == false // 没有禁用
                             && listAreaId.Contains(l.AreaId)  //货区过滤
                             && l.LockType == 0  //锁定过滤
                             && !lmLocal.Contains(l.Id) //库存过滤
                             && !trayLocal.Contains(l.Id) // 托盘过滤
                             select new { l.Id };

            //TODO:可以做到从数据库随机取一个
            var count = await LocalQuery.CountAsync();
            if (count == 0) return null;
            var skip = RandomHelper.Next(0, count - 1);
            var result = await LocalQuery.Skip(skip).Take(1).FirstOrDefaultAsync();

            //锁定货位
            await Db.UpdateSqlAsync<PB_Location>(w => w.Id == result.Id, ("LockType", UpdateType.Equal, 1));

            return result.Id;
        }

        public   async Task<TD_InStorageinfo> GetTD_InStorageinfo(string ParentId)
        {
            Expression<Func<TD_InStorage, Base_Department,PB_Equipment,Base_User, TD_InStorageinfo>> select = (a,b, c, d) => new TD_InStorageinfo
            {
                StorIdName=b.Name,
            };
            select = select.BuildExtendSelectExpre();
            var q = from a in GetIQueryable().AsExpandable()
                    join b in Db.GetIQueryable<Base_Department>() on a.StorId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()
                    join c in Db.GetIQueryable<PB_Equipment>() on a.EqId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Db.GetIQueryable<Base_User>() on a.AuditUserId equals d.Id into ad
                    from d in ad.DefaultIfEmpty()
                    select @select.Invoke(a,b, c, d);
            TD_InStorageinfo listdata = new TD_InStorageinfo();
            var qdata = await q.Where(x => x.Id == ParentId).FirstOrDefaultAsync();

            Expression<Func<TD_InStorDetail, Base_Department,PB_Location,PB_StorArea,PB_Rack,PB_Material,PB_PackList, PB_Tray, PB_TrayZone,PB_ProductionOrder,TD_InStorDetailDTO>> selects = (a, b, c, d, e, f, g,h,j,p) => new TD_InStorDetailDTO
            {
                MaterialIdName=f.Name,
                LocalIdName=c.Name,
                StorIdName=b.Name,
                AreaIdName=d.Name,
                Renwu=p.POName,
                Weight=f.Weight,
                Spce=f.Spec,
                RackIdName=e.Name,
            };
            selects = selects.BuildExtendSelectExpre();
            var k = from a in Db.GetIQueryable<TD_InStorDetail>().AsExpandable()
                    join b in Db.GetIQueryable<Base_Department>() on a.StorId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()

                    join c in Db.GetIQueryable<PB_Location>() on a.LocalId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()

                    join d in Db.GetIQueryable<PB_StorArea>() on c.AreaId equals d.Id into cd
                    from d in cd.DefaultIfEmpty()

                    join e in Db.GetIQueryable<PB_Rack>() on c.RackId equals e.Id into ce
                    from e in ce.DefaultIfEmpty()

                    join f in Db.GetIQueryable<PB_Material>() on a.MaterialId equals f.Id into af
                    from f in af.DefaultIfEmpty()

                    join g in Db.GetIQueryable<PB_PackList>() on a.PackId equals g.Id into ag
                    from g in ag.DefaultIfEmpty()

                    join h in Db.GetIQueryable<PB_Tray>() on a.TrayId equals h.Id into ah
                    from h in ah.DefaultIfEmpty()

                    join j in Db.GetIQueryable<PB_TrayZone>() on a.ZoneId equals j.Id into aj
                    from j in aj.DefaultIfEmpty()

                    join p in Db.GetIQueryable<PB_ProductionOrder>() on a.TaskId equals p.Id into ap
                    from p in ap.DefaultIfEmpty()
                    select @selects.Invoke(a, b, c, d, e, f, g,h,j,p);
            k = k.Where(x => x.InStorId == qdata.Id);
            var res = await k.ToListAsync();
            TD_InStorageinfo pblist = new TD_InStorageinfo();
            pblist.Id = qdata.Id;
            pblist.RecId = qdata.RecId;
            pblist.Code = qdata.Code;
            pblist.InStorTime = qdata.InStorTime;
            pblist.InType = qdata.InType;
            pblist.RefCode = qdata.RefCode;
            pblist.Status = qdata.Status;
            pblist.Remarks = qdata.Remarks;
            pblist.StorId = qdata.StorId;
            pblist.AddrId = qdata.AddrId;
            pblist.SupId = qdata.SupId;
            pblist.TotalNum = qdata.TotalNum;
            pblist.TotalAmt = qdata.TotalAmt;
            pblist.EqId = qdata.EqId;
            pblist.AuditUserId = qdata.AuditUserId;
            pblist.AuditeTime = qdata.AuditeTime;
            pblist.CreateTime = qdata.CreateTime;
            pblist.CreatorId = qdata.CreatorId;
            pblist.StorIdName = qdata.StorIdName;
            pblist.Deleted = qdata.Deleted;
            pblist.QrCode = qdata.QrCode;

            pblist.Subdata = res;
            if (res != null)
            {
                return pblist;
            }
            else
            {
                throw new BusException("暂无数据");
            }

        }




        public  async Task<PageResult<TD_InStorage>> GetDataListAsyncGroup(TD_InStoragePageInput input)
        {
            Expression<Func<TD_InStorage, Base_EnumItem, TD_Receiving, Base_EnumItem, TD_InStorageDTO>> select = (a, b, c, d) => new TD_InStorageDTO
            {
                TypeName = b.Name,
                ReCode = c.Code,
                ReceType = d.Name
            };
            select = select.BuildExtendSelectExpre();
            var q = from a in GetIQueryable().AsExpandable()
                    join b in Db.GetIQueryable<Base_EnumItem>() on a.InType equals b.Code into ab
                    from b in ab.Where(u => u.EnumCode.Contains("InStorageType")).DefaultIfEmpty()
                    join c in Db.GetIQueryable<TD_Receiving>() on a.RecId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Db.GetIQueryable<Base_EnumItem>() on c.Type equals d.Code into cd
                    from d in cd.Where(u => u.EnumCode.Contains("ReceiveType")).DefaultIfEmpty()
                    select @select.Invoke(a, b, c, d);
            //q = q
            //    .Include(i => i.Supplier)
            //    .Include(i => i.CreateUser)
            //    .Include(i => i.AuditUser)
            //    .Include(i => i.ReCode).Where(w => _operator.Property.DeptIds.Contains(w.StorId));
            q = q.Where(w => _operator.Property.DeptIds.Contains(w.DepId));
            var where = LinqHelper.True<TD_InStorage>();
            var search = input.Search;
            //如果物料不为空 和 货位 
            if (!search.MaterialName.IsNullOrEmpty() || !search.LocalName.IsNullOrEmpty() || !search.ConfirmUserIdName.IsNullOrEmpty())
            {
                //TD_InStorDetail  子表
                Expression<Func<TD_InStorDetail, PB_Material, PB_Location, Base_User, TD_InStorDetailDTO>> selectsk = (a, b, c, d) => new TD_InStorDetailDTO
                {
                    MaterialIdName = b.Name,
                    LocalIdName = c.Name,
                    ConfirmUserIdName = d.RealName
                };
                selectsk = selectsk.BuildExtendSelectExpre();
                var k = from a in Db.GetIQueryable<TD_InStorDetail>().AsExpandable()
                        join b in Db.GetIQueryable<PB_Material>() on a.MaterialId equals b.Id into ab
                        from b in ab.DefaultIfEmpty()
                        join c in Db.GetIQueryable<PB_Location>() on a.LocalId equals c.Id into ac
                        from c in ac.DefaultIfEmpty()
                        join d in Db.GetIQueryable<Base_User>() on a.CreatorId equals d.Id into ad
                        from d in ad.DefaultIfEmpty()

                        select @selectsk.Invoke(a, b, c, d);
                if (!search.MaterialName.IsNullOrEmpty())
                    k= k.Where(x => x.MaterialIdName.Contains(search.MaterialName));
                if (!search.LocalName.IsNullOrEmpty())
                    k = k.Where(x => x.LocalIdName.Contains(search.LocalName));
                if (!search.ConfirmUserIdName.IsNullOrEmpty())
                    k = k.Where(x => x.ConfirmUserIdName.Contains(search.ConfirmUserIdName));

                var res = await k.ToListAsync();
                // var res = await k.Where(x => x.MaterialIdName.Contains(search.MaterialName) || x.LocalIdName.Contains(search.LocalName) || x.ConfirmUserIdName.Contains(search.ConfirmUserIdName)).ToListAsync();
                var list = res.GroupBy(x => new { x.InStorId }).Select(x => new { InStorId = x.Key.InStorId });
                List<String> names = new List<string>();
                foreach (var item in list)
                {
                    names.Add(item.InStorId);
                }
                q = q.Where(x => names.Contains(x.Id));
            }





            if (!search.Code.IsNullOrEmpty())
                where = where.And(w => w.Id.Contains(search.Code) || w.RecId.Contains(search.Code));
            if (!search.InType.IsNullOrEmpty())
                where = where.And(w => w.InType == search.InType);
            if (!search.Rukuid.IsNullOrEmpty())
                where = where.And(w => w.Id.Contains(search.Rukuid));
            if (search.InStorTimeStart.HasValue)
                where = where.And(w => w.InStorTime >= search.InStorTimeStart.Value);
            if (search.InStorTimeEnd.HasValue)
                where = where.And(w => w.InStorTime <= search.InStorTimeEnd.Value);
            if (search.Status.HasValue)
                where = where.And(w => w.Status == search.Status.Value);
            q = q.Where(x=>x.InType==search.Type);
            return await q.Where(where).GetPageResultAsync(input);
        }

        public async Task<AjaxResult> SaveToExamine(string idIn, bool judge)
        {
            int Return = 0;
            string returnValue = string.Empty;
            if (judge)
            {
                Db.ExecuteSql(@" UPDATE IT_LocalMaterial table1
INNER JOIN(
    SELECT

        a.Id,
        b.Num

    FROM

        IT_LocalMaterial a

        INNER JOIN(SELECT * FROM TD_InStorDetail WHERE InStorId = '" + idIn + "') b ON a.MaterialId = b.MaterialId  WHERE a.StorId IN(SELECT StorId FROM TD_InStorDetail WHERE InStorId = '" + idIn + "')  AND a.LocalId IN(SELECT LocalId FROM TD_InStorDetail WHERE InStorId = '" + idIn + "') AND a.MaterialId IN(SELECT MaterialId FROM TD_InStorDetail WHERE InStorId = '" + idIn + "') ) table2 ON table1.id = table2.id SET table1.CheckNum =  table1.CheckNum+table2.Num ");
                Return = Db.ExecuteSql("UPDATE  TD_InStorage set Status=1  where Id='" + idIn + "' ");

                //为完工入库审核通过增加台账记录。牟俊明。
                //var bookSvc = _ServiceProvider.GetRequiredService<IIT_RecordBookBusiness>();
                //returnValue = await bookSvc.AddByTypeAsync(idIn, "In");
            }
            else
            {
                Return = Db.ExecuteSql("UPDATE TD_InStorage  set Status=2 where Id='" + idIn + "' ");
            }
            if (Return > 0)
            {
                AjaxResult res = new AjaxResult
                {
                    Success = true,
                    Msg = "请求成功！"
                };

                return res;
            }
            else
            {
                AjaxResult res = new AjaxResult
                {
                    Success = false,
                    Msg = "提交数据有误！"
                };

                return res;
            }
        }
    }
}